﻿using System.Reflection;
using AspectCore.DynamicProxy;
using AspectCore.DynamicProxy.Parameters;
using Microsoft.AspNetCore.DataProtection.KeyManagement;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Service.Core.Redis.DistributedLock;
using Service.Core.Redis.Services;
using Service.Framework;
using System.Threading;
using AspectCore.Extensions.Reflection;
using Refit;
using System.Xml.Linq;

namespace Service.Core.Redis.Aop.Cache
{
    /// <summary>
    /// 分布式redis锁拦截器
    /// </summary>
    public class DistributedLockInterceptorAttribute : DefaultInterceptor
    {
        public string[] ParameterNames { get; set; }

        public Type ParameterType { get; set; }

        private TimeSpan ExpiryTime { get; set; }
        private TimeSpan WaitTime { get; set; }

        private TimeSpan RetryTime { get; set; }
        public override int Order => 0;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="parameterName"></param>
        /// <param name="parameterType"></param>
        /// <param name="expiryTime"></param>
        /// <param name="waitTime"></param>
        /// <param name="retryTime"></param>
        public DistributedLockInterceptorAttribute(string[] parameterName, Type parameterType, long expiryTime = 60, long waitTime = 10, long retryTime = 1)
        {
            ParameterNames = parameterName;
            ParameterType = parameterType;
            ExpiryTime = TimeSpan.FromSeconds(expiryTime);
            WaitTime = TimeSpan.FromSeconds(waitTime);
            RetryTime = TimeSpan.FromSeconds(retryTime);
        }

        public override async Task Invoke(AspectContext context, AspectDelegate next)
        {
            var distributedLockService = context.ServiceProvider.GetRequiredService<IDistributedLockService>();

            var logger = context.ServiceProvider.GetRequiredService<ILogger<DistributedLockInterceptorAttribute>>();
            if (distributedLockService == null)
                throw new ArgumentNullException(nameof(distributedLockService));

            var key = GetKey(context);
            var acquireLock = await distributedLockService.AcquireLockAsync(key,
                                 ExpiryTime, WaitTime,
                                 RetryTime);
            logger.LogInformation("锁获取结果：{IsAcquired}", acquireLock.IsAcquired);
            if (acquireLock.IsAcquired)
            {
                try
                {
                    await next(context);
                }
                catch (Exception e)
                {
                    logger.LogError("DistributedLockInterceptorAttribute：错误：{Message}", e.Message);
                    throw new LogicErrorException(e.Message);
                }
                finally
                {
                    //释放锁
                    await acquireLock.DisposeAsync();
                }
            }
            else
            {
                logger.LogInformation("{Key}：额度锁定，当前业务正在处理中，等待锁释放。", key);
            }
        }



        private string GetKey(AspectContext context)
        {
            var name = context.ProxyMethod.Name;
            var prefix = context.ProxyMethod.DeclaringType?.FullName;
            return $"{prefix}:{name}:{GetDefaultKey(context, "", ParameterNames, ParameterType)}";
        }
    }
}
